package at.jku.ssw.fortress.ui.assistant;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.swt.graphics.Image;

import at.jku.ssw.fortress.ui.ImageConstants;
import at.jku.ssw.fortress.util.ImageManager;

public class ContentAssistProcessor implements IContentAssistProcessor, ICompletionListener {

	private static final String[] keywords = { "BIG", "SI", "unit", "absorbs", "abstract",
			"also", "api", "as", "asif", "at", "atomic", "bool", "case", "catch", "coerces",
			"coercion", "component", "comprises", "default", "dim", "do", "elif", "else",
			"end", "ensures", "except", "excludes", "exit", "export", "extends", "finally",
			"fn", "for", "forbid", "from", "getter", "hidden", "ident", "idiom", "if",
			"import", "in", "int", "invariant", "io", "juxtaposition", "label", "largest",
			"nat", "object", "of", "or", "opr", "private", "property", "provided", "requires",
			"self", "settable", "setter", "smallest", "spawn", "syntax", "test", "then",
			"throw", "throws", "trait", "transient", "try", "tryatomic", "type", "typecase",
			"unit", "value", "var", "where", "while", "widening", "widens", "with", "wrapped" };

	private List<Proposal> keywordProposals = new ArrayList<Proposal>();
	private List<Proposal> unicodeProposals = new ArrayList<Proposal>();
	

	private ImageManager imageManager = new ImageManager();
	private Image KEYWORD = imageManager.getImage(ImageConstants.ICON_KEYWORD);

	private final ContentAssistant assistant;

	public ContentAssistProcessor(ContentAssistant assistant) {
		this.assistant = assistant;
		for (String kw : keywords) {
			keywordProposals.add(new Proposal(kw, null, KEYWORD, kw));
		}
		UnicodeProposer up = new UnicodeProposer();
		unicodeProposals = up.getProposals();
	}

	private String prefix(String code, int offset) {
		char[] c = code.toCharArray();
		int pos = offset - 1;
		while (pos >= 0 && Character.isJavaIdentifierPart(c[pos])) {
			pos--;
		}
		return code.substring(pos + 1, offset);
	}

	public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
		return null;
	}

	public char[] getCompletionProposalAutoActivationCharacters() {
		return null;
	}

	public char[] getContextInformationAutoActivationCharacters() {
		return null;
	}

	public IContextInformationValidator getContextInformationValidator() {
		return null;
	}

	public String getErrorMessage() {
		return null;
	}
	
	private List<Proposal> proposals;

	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, final int offset) {
		final String prefix = prefix(viewer.getDocument().get(), offset);
		final int prefixLen = prefix.length();
		
		if (newSession) {
			ContextSensitiveAssist csa = new ContextSensitiveAssist();
			List<Proposal> contextProposals = csa.computeCompletionProposals(viewer
					.getDocument().get(), offset);

			proposals = new ArrayList<Proposal>();
			proposals.addAll(contextProposals);
			proposals.addAll(keywordProposals);
			proposals.addAll(unicodeProposals);
			newSession = false;
		}

		proposals = filter(proposals, new Matcher<Proposal>() {
			public boolean match(Proposal t) {
					return t.name.startsWith(prefix);
			}
		});

		List<ICompletionProposal> completionProposals = map(proposals,
				new Mapper<Proposal, ICompletionProposal>() {
					public ICompletionProposal map(Proposal s) {
						return new CompletionProposal(s.replacement, offset - prefixLen,
								prefixLen, s.replacement.length(), s.image, s.display, null,
								s.descripton);
					}
				});
		return completionProposals.toArray(new ICompletionProposal[0]);
	}

	private List<CompletionProposal> createCompletionProposals(List<Proposal> proposals) {
		List<CompletionProposal> res = new ArrayList<CompletionProposal>();
		return res;
	}

	public interface Matcher<T> {
		public boolean match(T t);
	}

	public interface Mapper<S, T> {
		public T map(S s);
	}

	public <T> List<T> filter(List<T> list, Matcher<T> matcher) {
		List<T> res = new ArrayList<T>();
		for (T t : list) {
			if (matcher.match(t)) {
				res.add(t);
			}
		}
		return res;
	}

	public <S, T> List<T> map(List<S> list, Mapper<S, T> mapper) {
		List<T> res = new ArrayList<T>();
		for (S s : list) {
			res.add(mapper.map(s));
		}
		return res;
	}
	
	private boolean newSession = false;

	public void assistSessionStarted(ContentAssistEvent event) {
		newSession = true;
	}

	public void assistSessionEnded(ContentAssistEvent event) {
	}

	public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
	}

}
